#include "photonMap.h"
#include <algorithm>


photonMap::photonMap()
{
	avarageSamplePower=0.0;
}
photonMap::~photonMap()
{
	
}
void photonMap::addPhoton(photon Photon, unsigned int lightNr)
{
	map.at(lightNr)->push_back(new photon(Photon));
	a = ( Photon.getPosition().x - zp.x ) / cubeSize;
	b = ( Photon.getPosition().y - zp.y ) / cubeSize;
	c = ( Photon.getPosition().z - zp.z ) / cubeSize;
	divisionStructure.at( (a* zDivs) + b*(zDivs*xDivs) + c )->photons.push_back(map.at(lightNr)->back());
}
void photonMap::delPhoton(unsigned int nr)
{

}
void photonMap::declareLightsNumber(unsigned int n)
{
	map.resize(n);
	for(unsigned int i(0); i<n; i++)
		map.at(i) = new std::vector<photon*>;
}
unsigned int photonMap::getLightsPhotonCount(unsigned int nr)
{
	if(nr<map.size())
		return map.at(nr)->size();
	else
		return 0;
}
unsigned int photonMap::getPhotonCount()
{
	unsigned int count(0);
	for(unsigned int i(0); i< map.size(); i++)
		count+=map.at(i)->size();
	return count;
}
void photonMap::scalePhotonPower(unsigned int lightNr, double factor)
{
	if(lightNr<map.size())
	{
		for(unsigned int i(0); i<map.at(lightNr)->size(); i++)
			map.at(lightNr)->at(i)->scalePower(factor);
	}
	else
	{
		return;
	}		
}
void photonMap::countAvarageSamplePower(unsigned int photonCount)
{
	avarageSamplePower = (double)photonCount/(double)getPhotonCount();


	minPhotonPower = 1.0;
	maxPhotonPower = 0.0;
	
	for(unsigned int i(0); i<map.size(); i++)
	{
		if(map.at(i)->size()!=0)
		{
			minPhotonPower = std::min(minPhotonPower, map.at(i)->at(0)->getPower());
			maxPhotonPower = std::max(maxPhotonPower, map.at(i)->at(0)->getPower());
		}
	}
	//avarageSamplePower-=(minPhotonPower*(double)photonCount);
	avarageSamplePower/=(maxPhotonPower*(double)photonCount);
}
double photonMap::getAvarageSamplePower()
{
	return avarageSamplePower;
}
double photonMap::getMinPhotonPower()
{
	return minPhotonPower;
}
double photonMap::getMaxPhotonPower()
{
	return maxPhotonPower;
}
unsigned int photonMap::getPhotonsFromSphere(point center, double *radius, color *intense, double *power, double maxRadius, unsigned int maxPhotons)
{
	currentPhotons.resize(0);
	double dist(0.0);

	a = ( center.x - zp.x ) / cubeSize;
	b = ( center.y - zp.y ) / cubeSize;
	c = ( center.z - zp.z ) / cubeSize;
	sceneDivCube* thisOne = divisionStructure.at( (a* zDivs) + b*(zDivs*xDivs) + c );
	for(unsigned int i(0); i< thisOne->neighbors.size(); i++)
	{
		tempPhotons.swap(thisOne->neighbors.at(i)->getPhoton(center,maxRadius));
		for(unsigned int j(0); j<tempPhotons.size(); j++)
		{
			currentPhotons.push_back( new cccComboBreaker(*tempPhotons.at(j)));
			*radius = std::max(*radius,tempPhotons.at(j)->d);
			delete tempPhotons.at(j);
		}
	}
	tempPhotons.resize(0);

	if(currentPhotons.size()>maxPhotons)
	{
		sort( currentPhotons.begin(), currentPhotons.end() );
		for(unsigned int i(maxPhotons); i< currentPhotons.size(); i++)
			delete currentPhotons.at(i);
		currentPhotons.resize(maxPhotons);
		for(unsigned int i(0); i < currentPhotons.size(); i++)
			*radius = currentPhotons.back()->d;
	}
	if(currentPhotons.size()<maxPhotons)
		*radius = maxRadius;

	color tempColor;
	*power=0.0;
	for (unsigned int i(0); i < currentPhotons.size(); i++)
	{
		tempColor.add(currentPhotons.at(i)->p->getIntensity());	//Using add because + operator lunches the Validate function which is undesired here.
		*power += currentPhotons.at(i)->p->getPower();
		delete currentPhotons.at(i);
	}
	int photonCount(currentPhotons.size());

	if(photonCount!=0)
		tempColor/=photonCount;
	//tempColor.validate();

	*intense = tempColor;
	return photonCount;
}
void photonMap::cleerPhotonMap()
{
	for (unsigned int i(0); i< map.size(); i++)
		delete map.at(i);
}
void photonMap::subdivideScene(double cSize, point zeroPoint, point maxPoint)
{
	zp = zeroPoint;
	cubeSize = cSize;
	sceneSize = vector3(maxPoint.x - zeroPoint.x, maxPoint.y - zeroPoint.y, maxPoint.z - zeroPoint.z);
	xDivs = (int)(sceneSize.x / cubeSize);
	yDivs = (int)(sceneSize.y / cubeSize);
	zDivs = (int)(sceneSize.z / cubeSize);

	for(int i(0); i<= xDivs; i++)
	{
		for(int j(0); j<= yDivs; j++)
		{
			for(int k(0); k<= zDivs; k++)
			{
				divisionStructure.push_back(new sceneDivCube);
			}
		}
	}
}
void photonMap::createStructure()
{
	sceneDivCube* thisOne;
	for(int i(0); i<= xDivs; i++)
	{
		for(int j(0); j<= yDivs; j++)
		{
			for(int k(0); k<= zDivs; k++)
			{
				thisOne = divisionStructure.at( (i*zDivs) + (j*(zDivs*xDivs)) + k);
				for(int ni(std::max(0,i-1)); ni <= std::min(xDivs,i+1); ni++)
				{
					for(int nj(std::max(0,j-1)); nj <= std::min(yDivs,j+1); nj++)
					{
						for(int nk(std::max(0,k-1)); nk <= std::min(zDivs,k+1); nk++)
						{
							if (divisionStructure.at( (ni*zDivs) + (nj*(zDivs*xDivs)) + nk)->photons.size() !=0)
								thisOne->neighbors.push_back(divisionStructure.at( (ni*zDivs) + (nj*(zDivs*xDivs)) + nk));
						}
					}
				}
			}
		}
	}
}